﻿using Furion.DatabaseAccessor;
using Furion.DependencyInjection;
using Furion.DynamicApiController;
using Furion.FriendlyException;
using iWare.Wms.Core;
using Mapster;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Linq.Dynamic.Core;
using Yitter.IdGenerator;

namespace iWare.Wms.Application
{
    /// <summary>
    /// 任务列表服务
    /// </summary>
    [Route("api/WareTask")]
    [ApiDescriptionSettings("任务列表", Name = "WareTask", Order = 100)]

    public class WareTaskService : IDynamicApiController, ITransient
    {
        private readonly IRepository<WareArea, MasterDbContextLocator> _wareAreaRep;
        private readonly IRepository<CollectDeliveryDetails, MasterDbContextLocator> _collectDeliveryDetailsRep;
        private readonly IRepository<WareContainer, MasterDbContextLocator> _wareContainerRep;
        private readonly IRepository<WareLocation, MasterDbContextLocator> _wareLocationRep;
        private readonly IRepository<WareTask, MasterDbContextLocator> _wareTaskRep;
        private readonly IRepository<WareStock, MasterDbContextLocator> _wareStockRep;
        private readonly IRepository<WareSortOrder, MasterDbContextLocator> _wareSortOrderRep;
        private readonly IRepository<WareContainerVsMaterial, MasterDbContextLocator> _wareContainerVsMaterialRep;
        private readonly IRepository<WareLocationVsContainer, MasterDbContextLocator> _wareLocationVsContainerRep;
        private readonly IRepository<WareOrderDetails, MasterDbContextLocator> _wareOrderDetailsRep;

        #region 默认
        /// <summary>
        /// 默认
        /// </summary>
        /// <param name="stereoscopicRep"></param>
        /// <param name="wareAreaRep"></param>
        /// <param name="wareContainerRep"></param>
        /// <param name="wareLocationRep"></param>
        /// <param name="wareStockRep"></param>
        /// <param name="wareTaskRep"></param>
        /// <param name="wareSortOrderRep"></param>
        /// <param name="wareContainerVsMaterialRep"></param>
        /// <param name="wareLocationVsContainerRep"></param>
        /// <param name="collectDeliveryDetailsRep"></param>
        /// <param name="wareOrderDetailsRep"></param>
        public WareTaskService(
           IRepository<WareArea, MasterDbContextLocator> wareAreaRep,
           IRepository<CollectDeliveryDetails, MasterDbContextLocator> collectDeliveryDetailsRep,
           IRepository<WareContainer, MasterDbContextLocator> wareContainerRep,
           IRepository<WareLocation, MasterDbContextLocator> wareLocationRep,
           IRepository<WareTask, MasterDbContextLocator> wareTaskRep,
           IRepository<WareStock, MasterDbContextLocator> wareStockRep,
           IRepository<WareSortOrder, MasterDbContextLocator> wareSortOrderRep,
           IRepository<WareContainerVsMaterial, MasterDbContextLocator> wareContainerVsMaterialRep,
           IRepository<WareLocationVsContainer, MasterDbContextLocator> wareLocationVsContainerRep,
           IRepository<WareOrderDetails, MasterDbContextLocator> wareOrderDetailsRep
        )
        {
            _collectDeliveryDetailsRep = collectDeliveryDetailsRep;
            _wareAreaRep = wareAreaRep;
            _wareContainerRep = wareContainerRep;
            _wareLocationRep = wareLocationRep;
            _wareTaskRep = wareTaskRep;
            _wareStockRep = wareStockRep;
            _wareSortOrderRep = wareSortOrderRep;
            _wareContainerVsMaterialRep = wareContainerVsMaterialRep;
            _wareLocationVsContainerRep = wareLocationVsContainerRep;
            _wareOrderDetailsRep = wareOrderDetailsRep;
        }
        #endregion

        /// <summary>
        /// 分页查询任务
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpGet("Page")]
        public async Task<PageResult<WareTaskOutput>> Page([FromQuery] WareTaskSearch input)
        {
            var list = await _wareTaskRep.DetachedEntities
                .Where(input.TaskStatus != TaskStatusEnum.All, u => u.TaskStatus == input.TaskStatus)
                .Where(input.TaskType != TaskType.All, u => u.TaskType == input.TaskType)
                .Where(!string.IsNullOrEmpty(input.OrderNo), u => EF.Functions.Like(u.OrderNo, $"%{input.OrderNo.Trim()}%"))
                .Where(!string.IsNullOrEmpty(input.TaskNo), u => EF.Functions.Like(u.TaskNo, $"%{input.TaskNo.Trim()}%"))
                .Where(!string.IsNullOrEmpty(input.ContainerCode), u => EF.Functions.Like(u.ContainerCode, $"%{input.ContainerCode.Trim()}%"))
                .Where(!string.IsNullOrEmpty(input.CreatedUserName), u => EF.Functions.Like(u.CreatedUserName, $"%{input.CreatedUserName.Trim()}%"))
                .Where(!string.IsNullOrEmpty(input.SearchBeginTime), u => u.CreatedTime >= DateTime.Parse(input.SearchBeginTime.Trim()) &&
                 u.CreatedTime <= DateTime.Parse(input.SearchEndTime.Trim()))
                .OrderBy(u => u.TaskStatus)
                .ThenByDescending(u => u.CreatedTime)
                .ThenByDescending(u => u.UpdatedTime)
                .ProjectToType<WareTaskOutput>()
                .ToADPagedListAsync(input.PageNo, input.PageSize);

            foreach (var item in list.Rows)
            {
                var areaID = new long(); //定义所属库区

                if (item.TaskType == TaskType.In) //入库任务
                {
                    var wareLocation = await _wareLocationRep.FirstOrDefaultAsync(z => z.Code == item.ToLocationCode);
                    if (wareLocation != null) { areaID = wareLocation.AreaID; }
                }
                else if (item.TaskType == TaskType.Out) //出库任务
                {
                    var wareLocation = await _wareLocationRep.FirstOrDefaultAsync(z => z.Code == item.FromLocationCode);
                    if (wareLocation != null) { areaID = wareLocation.AreaID; }
                }
                else areaID = 0;

                // 查询所属库区
                var wareArea = await _wareAreaRep.FirstOrDefaultAsync(z => z.Id == areaID);
                item.ReservoirArea = wareArea != null ? wareArea.AreaName : "";
            }

            return list;
        }

        /// <summary>
        /// 任务强制完成
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost("TaskFinish")]
        [UnitOfWork]
        public async Task TaskFinish([FromBody] TaskCallbackInput input)
        {
            var taskModel = await _wareTaskRep.FirstOrDefaultAsync(p => p.Id == input.Id);
            if (taskModel.TaskStatus == TaskStatusEnum.Complete) throw Oops.Oh("任务已完成!");
            if (taskModel.TaskType == TaskType.In)  //入库
            {
                //检查容器
                var containerModel = await _wareContainerRep.FirstOrDefaultAsync(n => n.Code == taskModel.ContainerCode);
                //if (taskModel.OrderNo != "N/A" && containerModel.ContainerStatus != ContainerStatusEnum.zupan) throw Oops.Oh("托盘未进行组盘!");
                //用于判断空托
                if (taskModel.OrderNo == "N/A" && containerModel.ContainerStatus != ContainerStatusEnum.kongxian) throw Oops.Oh("托盘信息不存在!");

                //检查库位
                var locationModel = await _wareLocationRep.DetachedEntities.Where(p => p.Code == taskModel.ToLocationCode).FirstOrDefaultAsync();
                if (locationModel == null) throw Oops.Oh("库位不存在!");
                if (locationModel.LocationStatus != LocationStatusEnum.dairu) throw Oops.Oh("库位异常货!");

                //获取库位容器关系
                var wareLocationVsContainerModel = await _wareLocationVsContainerRep.FirstOrDefaultAsync(p => p.ContainerCode == containerModel.Code
                     && p.LocationVsContainerStatus == CommonStatus.ENABLE);
                if (wareLocationVsContainerModel == null)
                {
                    // 创建容器与库位关系表
                    wareLocationVsContainerModel = new WareLocationVsContainer()
                    {
                        LocationId = locationModel.Id,
                        LocationCode = locationModel.Code,
                        ContainerId = containerModel.Id,
                        ContainerCode = containerModel.Code,
                        LocationVsContainerStatus = CommonStatus.ENABLE
                    };
                    await _wareLocationVsContainerRep.InsertAsync(wareLocationVsContainerModel);
                }
                //更新容器状态为库位
                containerModel.ContainerStatus = ContainerStatusEnum.kuwei;
                await _wareContainerRep.UpdateAsync(containerModel);

                //更新库位状态为存货
                locationModel.LocationStatus = LocationStatusEnum.cunhuo;
                if (taskModel.OrderNo == "N/A") locationModel.IsEmptyContainer = YesOrNot.Y;
                else locationModel.IsEmptyContainer = YesOrNot.N;
                await _wareLocationRep.UpdateAsync(locationModel);

                //更新任务状态为完成
                taskModel.TaskStatus = TaskStatusEnum.Complete;
                await _wareTaskRep.UpdateAsync(taskModel);

                //物料托盘关系表
                var wmsMaterialContainerList = await _wareContainerVsMaterialRep.DetachedEntities
                    .Where(p => p.OrderNo == taskModel.OrderNo).ToListAsync();
                //更新库存
                foreach (var item in wmsMaterialContainerList)
                {
                    // 更新库存
                    var stockDetailModel = await _wareStockRep.FirstOrDefaultAsync(n => n.ContainerCode == item.ContainerCode
                    && n.ProjectCode == item.ProjectCode && n.Code == item.Code && n.SpecificationModel == item.SpecificationModel);

                    if (stockDetailModel != null)
                    {
                        stockDetailModel.StockQuantity = item.BindQuantity;
                        stockDetailModel.LocationCode = locationModel.Code;
                        stockDetailModel.CurrentQuantity = item.BindQuantity;
                        await _wareStockRep.UpdateAsync(stockDetailModel);
                    }
                    else
                    {
                        stockDetailModel = new WareStock()
                        {
                            ProjectCode = item.ProjectCode,
                            Code = item.Code,
                            Name = item.Name,
                            SpecificationModel = item.SpecificationModel,
                            Unit = item.Unit ?? "",
                            StockQuantity = item.BindQuantity,
                            CurrentQuantity = item.BindQuantity,
                            ContainerCode = item.ContainerCode,
                            LocationCode = locationModel.Code,
                            XuHao = item.XuHao ?? "",
                            BrandName = item.BrandName ?? "",
                            ExpirationTime = DateTimeOffset.Now,
                            CreatedTime = DateTimeOffset.Now,
                            UpdatedTime = DateTimeOffset.Now
                        };
                        await _wareStockRep.InsertAsync(stockDetailModel);
                    }
                }

                //空托
                if (taskModel.OrderNo == "N/A")
                {
                    var stockModel = new WareStock()
                    {
                        ProjectCode = "N/A",
                        Code = "N/A",
                        Name = "N/A",
                        SpecificationModel = "N/A",
                        Unit = "N/A",
                        StockQuantity = 1,
                        CurrentQuantity = 1,
                        ContainerCode = containerModel.Code,
                        LocationCode = locationModel.Code,
                        XuHao = "N/A",
                        BrandName = ""
                    };
                    await _wareStockRep.InsertAsync(stockModel);
                }
            }
            else //出库
            {
                //库位信息
                var locationModel = await _wareLocationRep.FirstOrDefaultAsync(p => p.Code == taskModel.FromLocationCode);
                if (locationModel == null) throw Oops.Oh("库位不存在!");
                if (locationModel.LocationStatus != LocationStatusEnum.daichu) throw Oops.Oh("库位异常货!");

                //容器信息
                var containerModel = await _wareContainerRep.FirstOrDefaultAsync(n => n.Code == taskModel.ContainerCode &&
                n.ContainerStatus == ContainerStatusEnum.kuwei);
                if (containerModel == null) throw Oops.Oh("托盘信息不存在!");

                //库位容器关系
                var lvcModel = await _wareLocationVsContainerRep.FirstOrDefaultAsync(p => p.ContainerCode == taskModel.ContainerCode
                   && p.ContainerId == containerModel.Id && p.LocationCode == locationModel.Code && p.LocationId == locationModel.Id
                   && p.LocationVsContainerStatus == CommonStatus.ENABLE);
                if (lvcModel == null) throw Oops.Oh("库位容器关系不存在!");


                //关系对应出库的物料状态
                var materialContainersList = await _wareContainerVsMaterialRep.Where(p => p.ContainerCode == taskModel.ContainerCode
                && p.ContainerVsMaterialStatus == CommonStatus.ENABLE).ToListAsync();

                //库存
                var materialStockList = await _wareStockRep.Where(n => n.ContainerCode == taskModel.ContainerCode
                && n.LocationCode == taskModel.FromLocationCode).ToListAsync();

                //构建出库物料和托盘关系
                var OrderNo = YitIdHelper.NextId().ToString();
                foreach (var item in materialContainersList)
                {
                    item.ContainerVsMaterialStatus = CommonStatus.DELETED;
                    await _wareContainerVsMaterialRep.UpdateAsync(item);
                    //新增正常新的组盘关系
                    var enableModel = new WareContainerVsMaterial()
                    {
                        ContainerId = item.ContainerId,
                        ContainerCode = item.ContainerCode,
                        ProjectCode = item.ProjectCode,
                        XuHao = item.XuHao,
                        Code = item.Code,
                        Name = item.Name,
                        SpecificationModel = item.SpecificationModel,
                        Unit = item.Unit,
                        InspectionMethod = item.InspectionMethod,
                        BrandName = item.BrandName,
                        MaterialId = item.MaterialId,
                        BindQuantity = item.BindQuantity,
                        ContainerVsMaterialStatus = CommonStatus.ENABLE,
                        OrderNo = OrderNo
                    };
                    await _wareContainerVsMaterialRep.InsertNowAsync(enableModel);
                }
                //禁用托盘库位关系
                lvcModel.LocationVsContainerStatus = CommonStatus.DELETED;
                await _wareLocationVsContainerRep.UpdateAsync(lvcModel);

                // 更新容器状态为分拣
                if (taskModel.OrderNo == "N/A")
                {
                    containerModel.ContainerStatus = ContainerStatusEnum.kongxian;
                }
                else
                {
                    var isExit = await _wareSortOrderRep.AnyAsync(p => p.ContainerCode == containerModel.Code && p.SortStatus != SortStatusEnum.Completed);
                    if (isExit)
                    {
                        containerModel.ContainerStatus = ContainerStatusEnum.fenjian;
                    }
                    else
                    {
                        containerModel.ContainerStatus = ContainerStatusEnum.zupan;
                    }
                }
                await _wareContainerRep.UpdateAsync(containerModel);

                //更新库位状态为“空闲”
                locationModel.LocationStatus = LocationStatusEnum.kongxian;
                locationModel.IsEmptyContainer = YesOrNot.N;
                await _wareLocationRep.UpdateAsync(locationModel);
                //更新任务状态
                taskModel.TaskStatus = TaskStatusEnum.Complete;
                await _wareTaskRep.UpdateAsync(taskModel);

                //清除库存对应库位
                //修改库存
                foreach (var item in materialStockList)
                {
                    item.LocationCode = "N/A";
                    //空托
                    if (taskModel.OrderNo == "N/A")
                    {
                        item.StockQuantity = 0;
                        item.CurrentQuantity = 0;
                    }
                    await _wareStockRep.UpdateAsync(item);
                }
            }

        }

        /// <summary>
        /// 更改优先级别
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost("UpdatePriority")]
        public async Task UpdatePriority([FromBody] UpdateTaskPriorityInput input)
        {
            var taskModel = await _wareTaskRep.FirstOrDefaultAsync(p => p.Id == input.Id);
            if (taskModel.TaskStatus != TaskStatusEnum.NotProgress) throw Oops.Oh("只有未执行的任务能进行更改优先级别!");
            taskModel.Priority = input.Priority;
            await _wareTaskRep.UpdateAsync(taskModel);
        }

        /// <summary>
        /// 删除任务
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost("Delete")]
        [UnitOfWork]
        public async Task Delete([FromBody] DeleteWareTaskInput input)
        {
            foreach (var item in input.Id)
            {
                #region 删除Les系统的任务
                var taskModel = await _wareTaskRep.FirstOrDefaultAsync(p => p.Id == item);
                if (taskModel.TaskStatus != TaskStatusEnum.NotProgress) throw Oops.Oh("只有未执行的任务才能进行删除!");

                if (taskModel.TaskType == TaskType.In)  //入库任务
                {
                    //查询分拣库位信息
                    var locationModel = await _wareLocationRep.FirstOrDefaultAsync(p => p.Code == taskModel.FromLocationCode && p.AreaID == 410594643796037);
                    if (locationModel != null && taskModel.TaskStatus == TaskStatusEnum.NotProgress)
                    {
                        locationModel.LocationStatus = LocationStatusEnum.cunhuo;
                        await _wareLocationRep.UpdateAsync(locationModel);
                    }

                    //locationModel.LocationStatus = LocationStatusEnum.kongxian;

                    //await _wareLocationRep.UpdateAsync(locationModel);

                    //// 删除库位与容器关系
                    //var lvcModel = await _wareLocationVsContainerRep.FirstOrDefaultAsync(z => z.ContainerCode == taskModel.ContainerCode &&
                    //z.LocationCode == taskModel.ToLocationCode && z.LocationVsContainerStatus == CommonStatus.ENABLE);
                    //if (lvcModel == null) throw Oops.Oh("数据不存在!");

                    //await _wareLocationVsContainerRep.DeleteAsync(lvcModel);
                }
                else //出库任务
                {
                    var locationModel = await _wareLocationRep.FirstOrDefaultAsync(p => p.Code == taskModel.FromLocationCode);
                    if (locationModel == null) throw Oops.Oh("库位不存在!");
                    if (locationModel.LocationStatus != LocationStatusEnum.daichu) throw Oops.Oh("库位异常货!");
                    locationModel.LocationStatus = LocationStatusEnum.cunhuo;
                    await _wareLocationRep.UpdateAsync(locationModel);

                    if(taskModel.TaskModel== TaskModel.ZIDONG)
                    {
                        var locationModelEnd = await _wareLocationRep.FirstOrDefaultAsync(p => p.Code == taskModel.ToLocationCode);
                        if (locationModelEnd == null) throw Oops.Oh("agv库位不存在!");
                        if (locationModelEnd.LocationStatus != LocationStatusEnum.dairu) throw Oops.Oh("agv库位异常货!");
                        locationModel.LocationStatus = LocationStatusEnum.kongxian;
                        await _wareLocationRep.UpdateAsync(locationModel);
                    }

                    ////还原库位与容器关系，停用更改为正常
                    //var wareLocationVsContainer = await _wareLocationVsContainerRep.FirstOrDefaultAsync(
                    //    n => n.LocationCode == locationModel.Code && n.LocationVsContainerStatus == CommonStatus.ENABLE);
                    //if (wareLocationVsContainer == null) throw Oops.Oh("托盘库位关系异常！");
                    //wareLocationVsContainer.LocationVsContainerStatus = CommonStatus.ENABLE;
                    //await _wareLocationVsContainerRep.UpdateAsync(wareLocationVsContainer);

                    ////删除容器与物料关系是停用的信息
                    //var materialContainerDisable = await _wareContainerVsMaterialRep.DetachedEntities
                    //    .Where(p => p.ContainerCode == taskModel.ContainerCode && p.ContainerVsMaterialStatus == CommonStatus.ENABLE).ToListAsync();
                    //foreach (var itemsub in materialContainerDisable)
                    //{
                    //    await _wareContainerVsMaterialRep.DeleteAsync(itemsub);
                    //}

                    //根据容器编号查询分拣信息
                    var sortModel = await _wareSortOrderRep.DetachedEntities
                        .Where(p => p.ContainerCode == taskModel.ContainerCode && p.SortStatus == SortStatusEnum.NotProgram).ToListAsync();
                    foreach (var itemsub in sortModel)
                    {
                        //查询单据明细
                        var orderDetails = await _wareOrderDetailsRep.FirstOrDefaultAsync(z => z.Id == itemsub.OrderDetailID);
                        if (orderDetails == null) continue;
                        orderDetails.ActualQuantity = 0;
                        await _wareOrderDetailsRep.UpdateAsync(orderDetails);

                        //库存信息
                        var wareStockModel = await _wareStockRep.FirstOrDefaultAsync(p => p.ContainerCode == orderDetails.ContainerCode
                        && p.Code == orderDetails.Code && p.ProjectCode == orderDetails.ProjectCode && p.SpecificationModel == orderDetails.SpecificationModel);
                        if (wareStockModel == null) continue;
                        wareStockModel.CurrentQuantity += orderDetails.OrderQuantity;
                        await _wareStockRep.UpdateAsync(wareStockModel);

                        //删除分拣信息
                        await _wareSortOrderRep.DeleteAsync(itemsub);
                    }
                }

                //删除任务信息
                await _wareTaskRep.DeleteNowAsync(taskModel);
                #endregion

                
            }
        }
    }
}

